library(tidyverse)
library(dplyr)
library(stringr)
library(lubridate)
library(sf)
library(leaflet)
library(leafpop)
library(htmltools)
library(scales)
library(highcharter)
library(reactable)
nj <-   do.call(rbind,
          lapply(list.files(path = "raw data/NJ/solar"), read.csv)) %>%
  rename('id' = TI.Application.Number, 
         'program' = Program, 
         'capacity' = Calculated.Total.System.Size,
         'segment' = Customer.Type, 
         'third' = Third.Party.Ownership,
         'contractor' = Contractor.Company, 
         'utility' = Electric.Utility.Name,
         'zip' = Premise.........................Zip, 
         'county' = County......................Code, 
         'type' = Interconnection, 
         'date' = Acceptance.Date) %>% 
  select(id, utility, capacity, date, zip, county, segment, contractor, third, program, type) %>% 
  mutate(date = dmy(date), 
         capacity = as.numeric(gsub(",","", capacity)),
         quarter = zoo::as.yearqtr(date, format = "%Y-%m-%d"),
         segment_x = case_when(
           type == 'Community Solar' ~ 'Community Solar',
           segment == 'Residential' ~ 'Residential',
           TRUE ~ 'Non-Residential'),
         utility = case_when(
           grepl("pse", utility, ignore.case = TRUE) ~ "PSEG",
           grepl("ac electric", utility, ignore.case = T) ~ "AC Electric",
           grepl("jcp", utility, ignore.case = T) ~ "JCP&L",
           grepl("rockland", utility, ignore.case = T) ~ 'O&R',
           TRUE ~ 'Other (muni/co-op)'
         )) %>% 
  filter(type != 'Grid Supply') %>% 
  distinct()

nj_quarter <- nj %>% 
  filter(date >= '2020-07-01') %>% 
  group_by(segment_x, quarter) %>% 
  summarise(cap = sum(capacity)/1000)

nj_seg <- nj %>% 
  filter(quarter == '2021 Q2') %>% 
  mutate(res_cap = if_else(segment_x == 'Residential', capacity, 0),
         com_cap = if_else(segment_x == 'Non-Residential', capacity, 0),
         cs_cap = if_else(segment_x == 'Community Solar', capacity, 0),
         month = month(date))

nj_com_seg <- nj_seg %>% 
  filter(segment_x == 'Non-Residential') %>% 
  mutate(segment = as.factor(case_when(
    grepl('School', segment) ~ 'School',
    TRUE ~ segment
  ))) %>% 
  group_by(segment) %>% 
  summarise(cap = sum(capacity),
            n = n(),
            mean = mean(capacity)) %>% 
  ungroup() %>% 
  mutate(share = cap/sum(cap))

New Jersey added r round(sum(nj_seg$capacity)/1000,2) MW of new distributed solar capacity to the interconnection queue in Q2 2021

nj_quarter %>%
  hchart('column', hcaes(x = as.factor(quarter), y = round(cap,2), group = segment_x)) %>% 
  hc_colors(c('#F37325', '#2490BD', "#47B970", '#1A2B40', '#b7b7b7', '#800000','#F8AA1A')) %>% 
  hc_plotOptions(series = list(stacking = 'normal')) %>% 
  hc_xAxis(title = '', labels = list(step = 1) #, minorTickInterval
  ) %>% 
  hc_yAxis(title = list(text = 'Quarterly capacity (MW)'), style = list(fontSize = "5.0vh"))

Of the r round(sum(nj_seg\(capacity[nj_seg\)segment_x == ‘Non-Residential’]/1000),2) MW of new capacity that was Non-Residential…

for (i in levels(nj_com_seg$segment)) {
  cat("- ", "**", round(nj_com_seg$cap[nj_com_seg$segment == i]/1000,2), "**", " MW was ", i, sep = "")
  cat("\n")
}
  • 163.8 MW was Commercial
  • 0.42 MW was Farm
  • 10.06 MW was Government Facility
  • 1.84 MW was Municipality
  • 9.57 MW was Non Profit
  • 30.48 MW was Public University
  • 18.87 MW was School
nj_com_seg %>% 
  hchart('pie', hcaes(x = segment, y = round(cap/1000,2)), name = "Capacity (MW)") %>% 
  hc_colors(c( '#2490BD', '#800000', '#F37325', "#47B970", '#1A2B40', '#b7b7b7', '#F8AA1A')) 

Where was new capacity added in Q2 2021?

nj_map <- nj_seg %>% 
  mutate(geoid2 = as.numeric(substr(zip,1,5))) %>% 
  filter(!geoid2 == 16807|!geoid2 == 17047) %>% 
  group_by(geoid2) %>% 
  summarise(cap = sum(capacity)/1000)

njmap <- st_read('raw data/NJ/acs2019_5yr_B01003_86000US08403.shp') %>% 
  mutate(geoid2 = as.numeric(substr(geoid,8,12))) %>% 
  filter(!name == 'New Jersey',
         !geoid2 == 10990, !geoid2 == 10969) %>% 
  left_join(nj_map, by = 'geoid2') # join capacity data to shapefile

zip <- read.csv('raw data/uszips.csv') %>% # dataset from US census bureau that matches zip codes to town names - to be used in interactive map popup
  select(zip, city) %>% 
  rename('geoid2' = 'zip')

nj_int <- left_join(njmap, zip, by = 'geoid2') %>% 
  mutate(cap = cap*1000,
         cap = round(cap,0), 
         cap2 = if_else(is.na(cap),0,cap)) 

map_pal <- c('#e0f1f9', '#2490BD') 

pal <- colorNumeric(palette = map_pal, domain = nj_int$cap, na.color = '#FFFFFF') # palette function for choropleth map
labels <- sprintf("<strong>%s</strong><br/> Zip code: %s<br/> Capacity Q2 2021: %s kW",
                  nj_int$city, paste(0, nj_int$geoid2, sep = ""), comma(nj_int$cap2)) %>% 
  lapply(HTML) # function for popup labels

map_int <- leaflet(nj_int) %>% addTiles() 
map_int %>% addPolygons(fillColor = ~pal(cap),
                        weight = 0.5,
                        opacity = 1,
                        color = "gray",
                        dashArray = "3",
                        fillOpacity = 0.7,
                        highlightOptions = highlightOptions(color = '#2a2a2a',
                                                            weight = 2,
                                                            dashArray = "",
                                                            fillOpacity = 0.7,
                                                            bringToFront = T),
                        label = labels,
                        labelOptions = labelOptions(
                          style = list("font-weight" = "normal", padding = "3px 8px"),
                          textsize = "15px",
                          direction = "auto",
                          opacity = 0.75)) %>% 
  addProviderTiles('Esri.WorldGrayCanvas')

Which utilities added the most capacity in Q2 2021?

nj_utility <- nj_seg %>%
  group_by(utility) %>% 
  summarise(cap = sum(capacity))

nj_ut_month <- nj_seg %>%
  group_by(utility, month) %>% 
  summarise(cap = sum(capacity)) %>% 
    mutate(month = factor(month, levels = c(4, 5, 6), labels = c('April', 'May', 'June'))) 
nj_utility %>% 
  hchart('pie', hcaes(x = utility, y = round(cap/1000,2)), name = "Capacity (MW)") %>% 
  hc_colors(c('#F37325', '#2490BD', "#47B970", '#b7b7b7', '#1A2B40', '#800000','#F8AA1A')) 
nj_ut_month %>% 
  hchart('column', hcaes(x = month, y = round(cap/1000, 2), group = utility)) %>% 
  hc_colors(c('#F37325', '#2490BD', "#47B970", '#b7b7b7', '#1A2B40', '#800000','#F8AA1A')) %>% 
  hc_plotOptions(series = list(stacking = 'normal')) %>% 
  hc_xAxis(title = '', labels = list(step = 1) #, minorTickInterval
  ) %>% 
  hc_yAxis(title = list(text = 'Monthly capacity (MW)'), style = list(fontSize = "5.0vh"))

Which developers added the most capacity in Q2 2021?

nj_seg <- nj_seg %>% 
  mutate(contractor = as.character(contractor)) %>% 
  mutate(dev_agg = case_when(
    grepl('tesla|solarcity|solar city', contractor, ignore.case = T) ~ 'Tesla/SolarCity',
    grepl('vivint|sunrun|sun run', contractor, ignore.case = T) ~ 'Vivint/SunRun',
    grepl('momentum', contractor, ignore.case = T) ~ 'Momentum Solar',
    grepl('vision', contractor, ignore.case = T) ~ 'Vision Solar',
    grepl('greenpower|green power', contractor, ignore.case = T) ~ 'Green Power Energy',
    grepl('orbit', contractor, ignore.case = T) ~ 'Orbit Energy & Power',
    grepl('sunpower|sun power', contractor, ignore.case = T) ~ 'SunPower Corporation',
    grepl('sunnymac', contractor, ignore.case = T) ~ 'SunnyMac',
    grepl('whitman', contractor, ignore.case = T) ~ 'Steve Whitman',
    grepl('evergreen', contractor, ignore.case = T) ~ 'Evergreen Energy',
    grepl('pfister', contractor, ignore.case = T) ~ 'Pfister Energy',
    grepl('national', contractor, ignore.case = T) ~ 'National Energy Partners',
    grepl('grid builder', contractor, ignore.case = T) ~ 'Grid Builders (owned by NextGrid)',
    grepl('suntuity', contractor, ignore.case = T) ~ 'Suntuity Solar',
    grepl('posigen', contractor, ignore.case = T) ~ 'Posigen NJ',
    grepl('freedom', contractor, ignore.case = T) ~ 'Freedom Forever NJ',
    grepl('entersolar', contractor, ignore.case = T) ~ 'EnterSolar',
    grepl('edf', contractor, ignore.case = T) ~ 'EDF Renewables Distributed Solutions',
    grepl('brightcore', contractor, ignore.case = T) ~ 'Brightcore',
    grepl('cents', contractor, ignore.case = T) ~ 'Solar Cents',
    TRUE ~ contractor
  ))

nj_dev_sum <- nj_seg %>% 
  group_by(dev_agg, segment_x) %>% 
  summarise(cap = sum(capacity),
            n = n(),
            mean = mean(capacity)) %>% 
  ungroup() %>% 
  mutate(share = cap/sum(cap)) %>% 
  arrange(desc(cap))

Top 10 developers in the residential segment:

nj_dev_sum %>% filter(segment_x == 'Residential') %>%
  head(10) %>%
  select(dev_agg, cap, n, share) %>% 
  mutate(share = paste(round(share*100,2), "%", sep = ""),
         cap = format(round(as.numeric(cap), 2), big.mark = ",")) %>% 
  knitr::kable(col.names = c("Developer", "Capacity (kW)", "Number of Projects", "Market Share"),
               digits = 2, align = 'l') %>% 
  kableExtra::kable_styling(bootstrap_options = "striped", full_width = T #position = 'left'
                            ) %>% 
  kableExtra::add_header_above(c("Q2 2021" = 4))
Q2 2021
Developer Capacity (kW) Number of Projects Market Share
Vivint/SunRun 6,772.50 684 2.42%
Vision Solar 4,060.29 437 1.45%
Bright Planet Solar 3,014.13 348 1.08%
Trinity Solar 2,816.43 357 1.01%
Momentum Solar 2,493.28 322 0.89%
Suntuity Solar 2,119.48 258 0.76%
SunPower Corporation 1,895.87 195 0.68%
Freedom Forever NJ 1,350.23 149 0.48%
Tesla/SolarCity 1,144.61 109 0.41%
Posigen NJ 961.14 111 0.34%

Top 10 developers in the commercial segment:

nj_dev_sum %>% filter(segment_x == 'Non-Residential') %>%
  head(10) %>%
  select(dev_agg, cap, n, share) %>% 
  mutate(share = paste(round(share*100,2), "%", sep = ""),
         cap = format(round(as.numeric(cap), 2), big.mark = ",")) %>% 
  knitr::kable(col.names = c("Developer", "Capacity (kW)", "Number of Projects", "Market Share"),
               digits = 2, align = 'l') %>% 
  kableExtra::kable_styling(bootstrap_options = "striped", full_width = T #position = 'left'
                            ) %>% 
  kableExtra::add_header_above(c("Q2 2021" = 4))
Q2 2021
Developer Capacity (kW) Number of Projects Market Share
Rutgers, The State University of New Jersey 26,179.20 27 9.35%
EnterSolar 22,059.13 24 7.88%
EDF Renewables Distributed Solutions 18,047.20 6 6.45%
Arosa Solar Energy Systems Inc 14,715.34 47 5.26%
Distributed Solar Operations, LLC 11,973.81 15 4.28%
HESP Construction, LLC 9,941.78 28 3.55%
RETTEW Field Services 8,508.24 1 3.04%
Solar Cents 8,443.48 11 3.02%
AEPS Electric, LLC 7,588.91 11 2.71%
Tore Electric Co Inc.  7,327.34 6 2.62%

Top 10 developers active in both segments:

nj_dev_sum2 <- nj_seg %>% 
  group_by(dev_agg) %>%
  summarise(cap = sum(capacity),
            res = sum(res_cap),
            com = sum(com_cap),
            n = n(),
            mean = mean(capacity)) %>% 
  ungroup() %>% 
  mutate(share = cap/sum(cap)) %>% 
  filter(res != 0 & com != 0) %>% 
  arrange(desc(cap)) %>% 
  head(10)
nj_dev_sum2 %>% 
  select(dev_agg, cap, res, com, mean) %>% 
  mutate(cap = format(round(as.numeric(cap), 2), big.mark = ","),
         res = format(round(as.numeric(res), 2), big.mark = ","),
         com = format(round(as.numeric(com), 2), big.mark = ","),
         mean = round(mean, 2)) %>% 
  knitr::kable(col.names = c("Developer", "Total Capacity (kW)", "Residential Capacity (kW)", "Non-Residential Capacity (kW)", "Average Total Capacity"),
               digits = 2, align = 'l') %>% 
  kableExtra::kable_styling(bootstrap_options = "striped", full_width = T #position = 'left'
                            ) %>% 
  kableExtra::add_header_above(c("Q2 2021" = 5))
Q2 2021
Developer Total Capacity (kW) Residential Capacity (kW) Non-Residential Capacity (kW) Average Total Capacity
Geoscape Solar 6,938.22 8.64 6,929.58 365.17
Green Power Energy 6,869.47 870.91 5,998.56 78.06
Vision Solar 4,085.49 4,060.29 25.20 9.31
Trinity Solar 3,332.43 2,816.43 516.00 9.28
Orbit Energy & Power 3,213.98 815.86 2,398.12 36.94
Bright Planet Solar 3,020.43 3,014.13 6.30 8.65
Powerlutions 2,973.35 888.51 2,084.84 38.12
Momentum Solar 2,498.72 2,493.28 5.44 7.74
National Energy Partners 2,279.32 38.46 2,240.86 162.81
Azimuth Renewable Energy 2,195.17 55.11 2,140.06 64.56

Filter data

nj_table <- nj_seg %>% 
  select(dev_agg, capacity, date, utility, segment, zip) %>% 
 # mutate('Number of Projects' = 1) %>% 
  rename('Developer' = dev_agg,
         'Capacity' = capacity,
         'Date' = date,
         'Utility' = utility,
         'Segment' = segment,
         'Zip Code' = zip)
reactable(nj_table, filterable = TRUE,
          columns = list(Capacity = colDef(filterable = FALSE)),
          searchable = TRUE,
          showPageSizeOptions = TRUE,
          pageSizeOptions = c(5,10,20,50),
          defaultPageSize = 10)